#!/usr/local/bin/python3
# -*- coding: utf-8 -*-

"""
@File    : tcp_server_interface.py
@Author  : Link
@Time    : 2022/10/23 12:59
@Mark    : @注册到Ui中
           @TCP是比较好实现分开管理的方式
           @Queen比较麻烦
"""
from typing import List

from PySide2.QtCore import QThread, Signal, QReadWriteLock, QByteArray
from PySide2.QtNetwork import QTcpServer, QTcpSocket

from BenchUtils.log_utils import Print


class AppTcpThread(QThread):
    """
    只收发TCP数据
    server会有多个子client, 所以要确认好, 比如用于debug的client和用于AutoRun的client
    如何让两个client不打架:
        @1. 在AutoRun的时候, 记住来的client的address, 并在AutoRun结束期间, 只收取AutoRun的client的信号
        @2. 在debug模式下, 传信息的时候告诉App我这个是debug过来的
        @3. 数据传输要给个协议, 最大1024字节够不够
    接收:
        @
    发送:
        @ 告诉fail到哪个BIN别了
    """
    sk: QTcpSocket = None
    lock = QReadWriteLock()

    def __init__(self, parent, socked_id, send: Signal = None, read: Signal = None):
        """
        这里的线程是一直新起的线程,是不能对app做太多操作的
        :param parent:
        :param socked_id:
        :param send:
        :param read: read要传递MainBus进来
        """
        super(AppTcpThread, self).__init__(parent)
        self.send = send
        self.read = read
        self.socked_id = socked_id
        self.send.connect(self.write)

    def run(self) -> None:
        Print.Info("tcp server listening")
        self.sk = QTcpSocket()  # 此时的QTcpSocket属于新的线程
        if not self.sk.setSocketDescriptor(self.socked_id):
            self.error.connect(self.sk.error)  # QThread的error信号连接到QTcpSocket的槽函数error()
            return
        # self.app.led_device.setChecked(True)
        self.sk.totalBytesToReceive = 0  # 要接收的文件的总大小
        self.sk.bytesReceived = 0  # 已接收的数据大小
        self.sk.readyRead.connect(self.onReadyRead)
        self.sk.disconnected.connect(self.onDisconnected)
        peer_address = self.sk.peerAddress().toString()
        peer_port = self.sk.peerPort()
        news = 'Connected with address {}, port {}'.format(peer_address, str(peer_port))
        Print.Info(news)
        # 线程需要调用exec进入事件循环，QTcpSocket才可以触发信号，写数据的时候调用flush,就可以成功发送数据
        self.exec_()

    def onReadyRead(self):
        """发送端每次socket.write(),服务器接收端都会发送readyRead信号，调用本函数"""
        bytes_size = self.sk.bytesAvailable()
        bytes_data: QByteArray = self.sk.read(bytes_size)
        data = bytes_data.data().decode('utf-8')
        self.read.emit(data)

    def write(self, data: str):
        bytes_data: QByteArray = QByteArray(data.encode("utf-8"))
        self.sk.write(bytes_data)
        self.sk.flush()

    def onDisconnected(self):
        try:
            peer_address = self.sk.peerAddress().toString()
            peer_port = self.sk.peerPort()
            news = 'Disconnected with address {}, port {}'.format(peer_address, str(peer_port))
            Print.Info(news)
            self.sk.close()
        except RuntimeError:
            pass
        except Exception as err:
            print(err)
        self.read = None
        self.send.disconnect(self.write)
        self.quit()  # socket关闭时也一并结束线程


class AppTcpServer(QTcpServer):
    def __init__(self, parent=None, send: Signal = None, read: Signal = None):
        super(AppTcpServer, self).__init__(parent)
        self.send = send
        self.read = read
        # self.thread_list: List[AppTcpThread] = []

    def incomingConnection(self, socked_id):
        thread = AppTcpThread(self.parent(), socked_id, send=self.send, read=self.read)
        # self.thread_list.append(thread)
        thread.finished.connect(thread.deleteLater)
        thread.start()

    # def disconnect_all(self):
    #     for thread in self.thread_list:
    #         try:
    #             if not thread.isRunning():
    #                 continue
    #             thread.quit()
    #             thread.wait()
    #             thread.deleteLater()
    #         except RuntimeError:
    #             pass
    #     self.thread_list.clear()
